#include <stdio.h>
#include <string.h>
#include "dict.h"
#include "list.h"
#include "attrib.h"

dict_p dict_new() {
	list_p dict = list_new();
	return (dict_p)dict;
}

void dict_free(dict_p dict) {
	attrib_p tmp;

	dict_to_first(dict);
	tmp = dict_remove(dict);
	while (tmp) {
		attrib_free(tmp);
		tmp = dict_remove(dict);
	}
	free(dict);
}

dict_p dict_add(dict_p dict, attrib_p attrib) {
	return list_add((list_p)dict, (void *)attrib);
}

dict_p dict_add_new(dict_p dict, char *key, char *value) {
	attrib_p attrib = attrib_new(key, value);

	if (attrib == NULL) return NULL;

	return dict_add(dict, attrib);
}

attrib_p dict_set_key(dict_p dict, char *key, char *value) {
	attrib_p attrib;

	dict_to_first(dict);

	attrib = dict_find_next_key(dict, key);
	if (attrib)
		attrib_set_value(attrib, value);
	else {
		dict_add_new(dict, key, value);
		attrib = dict_get(dict);
	}
	return attrib;
}

attrib_p dict_get(dict_p dict) {
	return (attrib_p)list_get((list_p)dict);
}

attrib_p dict_remove(dict_p dict) {
	return (attrib_p)node_free(list_remove((list_p)dict));
}

list_p dict_remove_attribs(attrib_p(*func)(dict_p,char*), dict_p dict, char *s) {
	list_p list = list_new();
	attrib_p tmp;

	tmp = func(dict, s);
	while (tmp) {
		list_add(list, (void *)dict_remove(dict));
		tmp = func(dict, s);
	}

	return list;
}

list_p dict_remove_keys(dict_p dict, char *key) {
	return dict_remove_attribs(dict_find_next_key, dict, key);
}

list_p dict_remove_values(dict_p dict, char *value) {
	return dict_remove_attribs(dict_find_next_value, dict, value);
}

int dict_is_empty(dict_p dict) {
	return list_is_empty((list_p)dict);
}

int dict_at_first(dict_p dict) {
	return list_at_first((list_p)dict);
}

void dict_to_first(dict_p dict) {
	list_to_first((list_p)dict);
}

attrib_p dict_next(dict_p dict) {
	return (attrib_p)list_advance((list_p)dict);
}

int dict_at_last(dict_p dict) {
	return list_at_end((list_p)dict);
}

attrib_p dict_find(char*(*func)(attrib_p), dict_p dict, char *s) {
	attrib_p tmp;

	tmp = dict_get(dict);
	while (tmp) {
		if (strcmp(func(tmp), s) == 0) {
			dict_next(dict);
			return tmp;
		}
		tmp = dict_next(dict);
	}

	return NULL;
}

attrib_p dict_find_next_key(dict_p dict, char *key) {
	 return dict_find(attrib_get_key, dict, key);
}

attrib_p dict_find_next_value(dict_p dict, char *value) {
	 return dict_find(attrib_get_value, dict, value);
}

list_p dict_find_all(attrib_p(*func)(dict_p,char*), dict_p dict, char *str) {
	list_p matches = list_new();
	attrib_p tmp;
	
	dict_to_first(dict);

	tmp = func(dict, str);
	while (tmp) {
		list_add(matches, (void *)tmp);
		tmp = func(dict, str);
	}

	return matches;
}

list_p dict_find_all_keys(dict_p dict, char *key) {
	return dict_find_all(dict_find_next_key, dict, key);
}

list_p dict_find_all_values(dict_p dict, char *value) {
	return dict_find_all(dict_find_next_value, dict, value);
}

attrib_p dict_find_next_match(dict_p dict, char *key, char *value) {
	attrib_p match = attrib_new(key, value);
	attrib_p attrib;

	attrib = dict_find_next_key(dict, key);
	while (attrib) {
		if (attrib_cmp(attrib, match) == 0)
			return attrib;
		attrib = dict_next(dict);
	}

	return NULL;
}

list_p dict_find_all_matches(dict_p dict, char *key, char *value) {
	list_p list = list_new();
	attrib_p attrib;

	attrib = dict_find_next_match(dict, key, value);
	while (attrib)
		list_add(list, attrib);

	return list;
}

